"""
第三方API Key鉴权工具
用于管理第三方系统调用的固定API Key验证
"""
import os
import re
from datetime import datetime
from typing import Optional, Set
from fastapi import HTTPException, status, Request
from src.utils.logging_config import logger
# 不再手动加载.env，因为在Docker环境中环境变量已经通过docker-compose加载


class APIKeyConfig:
    """API Key配置管理"""

    # 从环境变量读取API Key
    THIRD_PARTY_API_KEY = os.getenv("THIRD_PARTY_API_KEY", "")

    # API Key功能开关
    API_KEY_ENABLED = os.getenv("API_KEY_ENABLED", "true").lower() == "true"

    # 在类初始化时输出调试信息
    @classmethod
    def _debug_log_config(cls):
        logger.info(f"🔧 API Key配置调试:")
        logger.info(f"   THIRD_PARTY_API_KEY: {'已设置' if cls.THIRD_PARTY_API_KEY else '未设置'}")
        if cls.THIRD_PARTY_API_KEY:
            logger.info(f"   API_KEY前缀: {cls.THIRD_PARTY_API_KEY[:10]}...")
        logger.info(f"   API_KEY_ENABLED: {cls.API_KEY_ENABLED}")

    # API Key可访问的接口路径
    API_KEY_ALLOWED_PATHS = [
        r"^/api/system/health$",              # 健康检查
        r"^/api/system/info$",                # 系统信息
        r"^/api/knowledge/databases$",        # 知识库列表
        r"^/api/knowledge/databases/[^/]+/query$",  # 知识库查询
        r"^/api/graph/lightrag/databases$",   # 图数据库列表
        r"^/api/graph/lightrag/subgraph$",    # 图谱子图查询
        r"^/api/graph/neo4j/node$",           # 实体搜索
        r"^/api/chat/agent$",                 # 智能体列表
        r"^/api/chat/threads$",               # 对话线程列表
        r"^/api/chat/call$",                  # 对话调用
        r"^/api/tool/tools$",                 # 工具列表
        r"^/api/situation/geo-query$",        # 地理空间查询
        r"^/mcp.*$",                          # MCP协议和工具端点（合并为单一路径）
        r"^/api/mcp.*$",                      # API路由下的MCP工具端点
    ]

    # 可选的IP白名单（支持CIDR格式）
    API_KEY_ALLOWED_IPS = os.getenv("API_KEY_ALLOWED_IPS", "*").split(",")

    # 请求频率限制（每小时最多调用次数）
    API_KEY_RATE_LIMIT = int(os.getenv("API_KEY_RATE_LIMIT", "1000"))

    @classmethod
    def is_api_key_valid(cls, api_key: str) -> bool:
        """验证API Key是否有效"""
        if not cls.API_KEY_ENABLED:
            return False

        if not cls.THIRD_PARTY_API_KEY:
            logger.warning("未配置第三方API Key，请设置环境变量 THIRD_PARTY_API_KEY")
            return False

        # 使用常量时间比较防止时序攻击
        return api_key == cls.THIRD_PARTY_API_KEY

    @classmethod
    def is_path_allowed_for_api_key(cls, path: str) -> bool:
        """检查路径是否允许API Key访问"""
        path = path.rstrip('/')
        for pattern in cls.API_KEY_ALLOWED_PATHS:
            if re.match(pattern, path):
                return True
        return False

    @classmethod
    def is_ip_allowed(cls, client_ip: str) -> bool:
        """检查IP地址是否在白名单中"""
        # 如果设置为*，表示允许所有IP
        if "*" in cls.API_KEY_ALLOWED_IPS:
            return True

        # TODO: 实现更完善的IP匹配逻辑（支持CIDR）
        return client_ip in cls.API_KEY_ALLOWED_IPS


class APIKeyUsageTracker:
    """API Key使用跟踪器（简单内存实现，生产环境建议使用Redis）"""

    def __init__(self):
        # 记录API调用次数 {hour_key: count}
        self._usage_count: dict[str, int] = {}
        # 记录调用日志（限制大小防止内存溢出）
        self._call_logs: list[dict] = []
        self._max_logs = 1000

    def _get_current_hour_key(self) -> str:
        """获取当前小时的时间键"""
        return datetime.now().strftime("%Y%m%d%H")

    def record_usage(self, client_ip: str, path: str, success: bool, duration: float):
        """记录API调用"""
        hour_key = self._get_current_hour_key()

        # 更新使用计数
        if hour_key not in self._usage_count:
            # 清理旧数据
            self._cleanup_old_data()
            self._usage_count[hour_key] = 0

        self._usage_count[hour_key] += 1

        # 记录调用日志
        log_entry = {
            "timestamp": datetime.now().isoformat(),
            "client_ip": client_ip,
            "path": path,
            "success": success,
            "duration": duration
        }

        self._call_logs.append(log_entry)

        # 限制日志数量
        if len(self._call_logs) > self._max_logs:
            self._call_logs.pop(0)

    def is_rate_limit_exceeded(self, limit: int) -> bool:
        """检查是否超过频率限制"""
        hour_key = self._get_current_hour_key()
        current_count = self._usage_count.get(hour_key, 0)
        return current_count >= limit

    def _cleanup_old_data(self):
        """清理24小时前的旧数据"""
        current_hour = int(self._get_current_hour_key())
        keys_to_remove = []

        for key in self._usage_count.keys():
            if int(key) < current_hour - 24:
                keys_to_remove.append(key)

        for key in keys_to_remove:
            del self._usage_count[key]

    def get_stats(self) -> dict:
        """获取使用统计"""
        hour_key = self._get_current_hour_key()
        return {
            "current_hour_usage": self._usage_count.get(hour_key, 0),
            "hourly_limit": APIKeyConfig.API_KEY_RATE_LIMIT,
            "recent_logs": self._call_logs[-100:]  # 最近100条记录
        }


# 全局API Key使用跟踪器实例
api_key_tracker = APIKeyUsageTracker()


def validate_api_key(request: Request) -> Optional[str]:
    """
    验证请求中的API Key

    Args:
        request: FastAPI请求对象

    Returns:
        如果验证通过返回'api_key'，否则返回None

    Raises:
        HTTPException: API Key验证失败时抛出
    """
    if not APIKeyConfig.API_KEY_ENABLED:
        return None

    # 从Header获取API Key
    api_key = request.headers.get("X-API-Key")

    # 如果Header中没有，尝试从Query参数获取
    if not api_key:
        api_key = request.query_params.get("api_key")

    if not api_key:
        return None

    # 验证API Key格式和有效性
    if not APIKeyConfig.is_api_key_valid(api_key):
        logger.warning(f"无效的API Key尝试: {api_key[:10]}... from {request.client.host}")
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="无效的API Key",
            headers={"WWW-Authenticate": "X-API-Key"}
        )

    # 检查IP白名单
    client_ip = request.client.host
    if not APIKeyConfig.is_ip_allowed(client_ip):
        logger.warning(f"API Key被拒绝访问，IP不在白名单: {client_ip}")
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="IP地址不在白名单中"
        )

    # 检查频率限制
    if api_key_tracker.is_rate_limit_exceeded(APIKeyConfig.API_KEY_RATE_LIMIT):
        logger.warning(f"API Key频率超限 from {client_ip}")
        raise HTTPException(
            status_code=status.HTTP_429_TOO_MANY_REQUESTS,
            detail=f"API调用频率超限，每小时最多{APIKeyConfig.API_KEY_RATE_LIMIT}次",
            headers={"Retry-After": "3600"}
        )

    return api_key


def get_client_info(request: Request) -> dict:
    """获取客户端信息"""
    return {
        "ip": request.client.host,
        "user_agent": request.headers.get("user-agent", "unknown"),
        "referer": request.headers.get("referer", "direct")
    }